use proc_macro::TokenStream;
use quote::quote;
use syn::{
    parse_macro_input, DeriveInput, Data, Fields, Attribute, Meta,
    punctuated::Punctuated, token::Comma
};

/// 主派生宏，增强 thiserror 的功能
#[proc_macro_derive(ErrorExt, attributes(thiserror_exts))]
pub fn error_exts_derive(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    
    let enum_name = &input.ident;
    let generics = &input.generics;
    
    // 处理枚举的每个变体
    let from_impls = match &input.data {
        Data::Enum(data_enum) => {
            data_enum.variants.iter().filter_map(|variant| {
                process_variant(variant, enum_name, generics)
            }).collect::<Vec<_>>()
        }
        _ => {
            return syn::Error::new_spanned(&input, "ErrorExt only works on enums")
                .to_compile_error()
                .into();
        }
    };
    
    let expanded = quote! {
        #(#from_impls)*
    };
    
    expanded.into()
}

/// 处理单个枚举变体
fn process_variant(
    variant: &syn::Variant,
    enum_name: &syn::Ident,
    generics: &syn::Generics,
) -> Option<proc_macro2::TokenStream> {
    let variant_name = &variant.ident;
    
    match &variant.fields {
        Fields::Named(fields) => process_named_fields(fields, variant_name, enum_name, generics),
        Fields::Unnamed(_) => None, // 不支持元组变体
        Fields::Unit => None, // 单元变体不需要 From 实现
    }
}

/// 处理命名字段的变体
fn process_named_fields(
    fields: &syn::FieldsNamed,
    variant_name: &syn::Ident,
    enum_name: &syn::Ident,
    generics: &syn::Generics,
) -> Option<proc_macro2::TokenStream> {
    // 查找有 from 属性的字段
    let from_field = fields.named.iter().find(|field| {
        has_from_attribute(&field.attrs)
    })?;
    
    // 检查是否所有非from字段都是implicit location字段
    let all_fields_valid = fields.named.iter().all(|field| {
        has_from_attribute(&field.attrs) || 
        (has_implicit_attribute(&field.attrs) && is_location_type(&field.ty))
    });
    
    if !all_fields_valid {
        return None;
    }
    
    Some(generate_from_impl_with_location(
        &from_field.ty,
        variant_name,
        enum_name,
        generics,
        &fields.named,
    ))
}

/// 检查字段属性中是否有 from 属性
fn has_from_attribute(attrs: &[Attribute]) -> bool {
    for attr in attrs {
        if attr.path().is_ident("thiserror_exts") {
            // 使用正确的 API 检查属性内容
            if let Meta::List(meta_list) = &attr.meta {
                // 检查 tokens 中是否包含 "from"
                let tokens_str = meta_list.tokens.to_string();
                if tokens_str.contains("from") {
                    return true;
                }
            }
        }
    }
    false
}

/// 检查字段属性中是否有 implicit 属性
fn has_implicit_attribute(attrs: &[Attribute]) -> bool {
    for attr in attrs {
        if attr.path().is_ident("thiserror_exts") {
            // 使用正确的 API 检查属性内容
            if let Meta::List(meta_list) = &attr.meta {
                // 检查 tokens 中是否包含 "implicit"
                let tokens_str = meta_list.tokens.to_string();
                if tokens_str.contains("implicit") {
                    return true;
                }
            }
        }
    }
    false
}

/// 为命名字段生成带位置追踪的 From 实现
fn generate_from_impl_with_location(
    source_type: &syn::Type,
    variant_name: &syn::Ident,
    enum_name: &syn::Ident,
    generics: &syn::Generics,
    all_fields: &Punctuated<syn::Field, Comma>,
) -> proc_macro2::TokenStream {
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
    
    // 构建字段初始化表达式
    let field_inits = all_fields.iter().map(|field| {
        let field_ident = field.ident.as_ref().unwrap();
        
        if has_from_attribute(&field.attrs) {
            // 这是 from 字段，使用传入的错误
            quote! { #field_ident: error }
        } else if has_implicit_attribute(&field.attrs) && is_location_type(&field.ty) {
            // 这是隐式 location 字段，使用捕获的位置信息
            quote! { #field_ident: thiserror_exts_impl::Location::new(l.file(), l.line(), l.column()) }
        } else {
            // 理论上不会执行到这里，因为我们已经检查过所有字段都是有效的
            quote! { #field_ident: todo!() }
        }
    });
    
    quote! {
        impl #impl_generics From<#source_type> for #enum_name #ty_generics #where_clause {
            #[track_caller]
            fn from(error: #source_type) -> Self {
                let l = std::panic::Location::caller();
                #enum_name::#variant_name {
                    #(#field_inits),*
                }
            }
        }
    }
}

/// 检查类型是否为 Location
fn is_location_type(ty: &syn::Type) -> bool {
    if let syn::Type::Path(type_path) = ty {
        if let Some(segment) = type_path.path.segments.last() {
            segment.ident == "Location"
        } else {
            false
        }
    } else {
        false
    }
}

